package com.telrob.bytevm.natives;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.telrob.bytevm.utils.ToolUtils;
import com.telrob.bytevm.vm.Param;
import com.telrob.bytevm.vm.Register;

/****
 * 将本地方法注册进去,
 * 
 * @author zrz
 *
 */
public class Natives {
	//方法列表
	private static Map<String, Method> mathodMap = new HashMap<String, Method>();
	//方法下表索引
	private static Map<String,Integer>methodIndex=new HashMap<String,Integer>();
	
	private static byte[]MathodTable=null;
	
	public static void main(String[] args) {
		Register R=new Register();
		call("print", R, (byte)0, null);
		call("test", R, (byte)0, null);
	}
	
	/****
	 * 获取方法在表中的下表
	 * @param name
	 * @return
	 */
	public static int getMethodIndex(String name) {
		Integer index=methodIndex.get(name);
		if(index==null) {
			index=0;
		}else {
			index=index+4;
		}
		return index;
	}
	/***
	 * 函数映射表
	 * @return
	 */
	public static byte[]getMethodTable(){
		if(MathodTable!=null) {
			return MathodTable;
		}
		
		ByteArrayOutputStream bout=new ByteArrayOutputStream();
		ByteArrayOutputStream bout2=new ByteArrayOutputStream();
		try {
			for(String key:mathodMap.keySet()) {
				int size=bout.size();
				methodIndex.put(key, size);
				byte[]name=key.getBytes();
				bout.write(name);
				//分隔符
				bout.write((byte)(0));
				//在数组中的下表
				bout.write((byte)(0));
				bout.write((byte)(0));
				bout.write((byte)(0));
				bout.write((byte)(0));
			}
			byte[]nameBate=bout.toByteArray();
			int len=nameBate.length+4;
			byte[] lenData=ToolUtils.int2bytes(len);
			bout2.write(lenData);
			bout2.write(nameBate);
			MathodTable=bout2.toByteArray();
		}catch(Exception e) {
			e.printStackTrace();
		}finally {
			try {
				bout.close();
			} catch (IOException e) {}
			try {
				bout2.close();
			} catch (IOException e) {}
		}
		
		return MathodTable;
	}
	
	
	
	/***
	 * 调用本地方法
	 * @param methodName 方法名称
	 * @param R 寄存器相关信息
	 * @param opt 
	 * @param data
	 */
	public static void call(String methodName, Register R, byte opt, byte[] data) {
		Method method=mathodMap.get(methodName);
		if(method!=null) {
			try {
				Param param=new Param(R, data);
				method.invoke(null, param);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	static {
		try {
			List<String> list = ToolUtils.scalePackage("com.telrob.bytevm.natives.simp");
			if (list != null && list.size() > 0) {
				for (String name : list) {
					Class<?> cls = Class.forName(name);
					Method[] mds = cls.getDeclaredMethods();
					if (mds != null && mds.length > 0) {
						for (Method md : mds) {
							NativeMethod ann = md.getAnnotation(NativeMethod.class);
							if (ann != null) {
								String methodName = ann.value();
								mathodMap.put(methodName, md);
							}

						}
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}
